package com.huonan.jb.tools.esuse.export.apps;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.setting.dialect.Props;
import cn.hutool.setting.dialect.PropsUtil;
import com.huonan.jb.tools.esuse.config.PropConfig;
import com.huonan.jb.tools.esuse.dto.EsHitsInfo;
import com.huonan.jb.tools.esuse.export.Constants;
import com.huonan.jb.tools.esuse.export.enums.Env;
import com.huonan.jb.tools.esuse.export.enums.FileType;
import com.huonan.jb.tools.esuse.export.es.SearchEs;
import com.huonan.jb.tools.esuse.export.type.ExportFile;
import com.huonan.jb.tools.esuse.export.utils.EsUtils;
import com.huonan.utils.DateHelper;
import com.huonan.utils.ExecutorUtil;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Description 通过文件中的账号和DSL查询es
 * @Author lxp
 * @Date 2023/2/6 下午2:31
 * @Version V1.0
 **/
@Slf4j
public class AppEsByFile {

    public static final int BATCH_SIZE = 1000;

    static String argFile = Constants.SQL_FILE;
    //导出数据格式。默认json
    static FileType fileType = FileType.JSON;
    static Env env = Env.PROD;
    private static AtomicInteger count = new AtomicInteger(0);

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        /*线程数=导数并行度（指定时间切分几分）*/
        int THREAD_SIZE = PropConfig.getThreadSize(argFile);
        ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_SIZE);
        Props props = PropsUtil.get(argFile);
        String srcFile = props.getStr("srcFile");
        List<String> list = FileUtil.readUtf8Lines(srcFile);
        // 根据文件内容 list，动态生成SQL
        //selectByDynamicSQL(threadPool, list);
        // 根据文件内容 list，动态生成index
        // selectByDynamicIndex(threadPool, list);
        // 固定dsl 查询
        selectByFixedSql(threadPool);
    }

    private static void selectByFixedSql(ExecutorService threadPool) {
        // sql 不变
        int THREAD_SIZE = PropConfig.getThreadSize(argFile);
        for (int i = 1; i <= THREAD_SIZE; i++) {
            Props props = EsUtils.getProps(THREAD_SIZE, 1, argFile);
            //记录文件编号
            props.setProperty("count", count.incrementAndGet());
            threadSearch(props, threadPool);
        }
        ExecutorUtil.closePool(threadPool);
    }

    private static void selectByDynamicIndex(ExecutorService threadPool, List<String> list) {
        for (String index : list) {
            //sql要重新生成，所以遍历每次要初始化
            Props newProps = new Props(argFile);
            newProps.setProperty("index", index);
            //记录文件编号
            newProps.setProperty("count", count.incrementAndGet());
            threadSearch(newProps, threadPool);
        }
        ExecutorUtil.closePool(threadPool);
    }

    private static void selectByDynamicSQL(ExecutorService threadPool, List<String> list) {
        List<List<String>> listList = ListUtil.split(list, BATCH_SIZE);
        List<String> formatList = formatList(listList);
        for (String id : formatList) {
            //sql要重新生成，所以遍历每次要初始化
            Props newProps = new Props(argFile);
            String formatDsl = formatDsl(id, newProps);
            newProps.setProperty("sql", formatDsl);
            //记录文件编号
            newProps.setProperty("count", count.incrementAndGet());
            threadSearch(newProps, threadPool);
        }
        ExecutorUtil.closePool(threadPool);
    }

    private static String formatDsl(String id, Props props) {
        String sql = props.getStr("sql");
        return String.format(sql, id);
    }

    @NotNull
    private static List<String> formatList(List<List<String>> listList) {
        List<String> listString = new ArrayList<>();
        for (List<String> stringList : listList) {
            StringJoiner joiner = new StringJoiner(",");
            for (String s : stringList) {
                joiner.add("\"" + s + "\"");
            }
            listString.add(joiner.toString());
        }
        return listString;
    }


    private static void threadSearch(Props props, ExecutorService threadPool) {
        CompletableFuture.runAsync(() -> {
            DateHelper.MonitorUtil.start();
            int searchCount = 0;
            String scrollId;
            while (true) {
                searchCount++;
                try {
                    EsHitsInfo dataResult = SearchEs.preHandler(env, true, props);
                    if (EsUtils.isContinue(dataResult)) continue;
                    JSONArray hits = dataResult.getHits();
                    if (EsUtils.isBreak(hits)) break;
                    scrollId = dataResult.getScrollId();
                    props.put("scrollId", scrollId);
                    ExportFile.exportHandle(props, dataResult, fileType);
                    log.info("{} 第:{}次,数据总量:{},本次导出数据量:{}", Thread.currentThread().getName(), searchCount,
                            dataResult.getHistTotal(), hits.size());
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error(e.getMessage());
                    return;
                }
            }
        }, threadPool);
    }

    private static void threadSearch2(Props props, ExecutorService threadPool) {
//        CompletableFuture.runAsync(() -> {
        DateHelper.MonitorUtil.start();
        int searchCount = 0;
        searchCount++;
        try {
            EsHitsInfo dataResult = SearchEs.preHandler(env, false, props);
            JSONArray hits = dataResult.getHits();
            String scrollId = dataResult.getScrollId();
            props.put("scrollId", "");
            ExportFile.exportHandle(props, dataResult, fileType);
            log.info("{} 第:{}次,数据总量:{},本次导出数据量:{}", Thread.currentThread().getName(), searchCount,
                    dataResult.getHistTotal(), hits.size());
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
            return;
        }
    }
}